import enum
import glob
import os
import random
import time
import traceback

import cv2
import uiautomation as auto
from pynput.keyboard import Key, Controller as KeyboardController

from zz import zz_log, zz_code, zz_img_cv, zz_return, zz_str
from game import zz_player_data

log = zz_log.of()

keyboard = KeyboardController()


class GameSpeed(enum.Enum):
    go = 430
    run = 970


def click(key, timeout=0.1):
    """
    点击
    """
    keyboard.press(key)
    time.sleep(timeout)
    keyboard.release(key)


def click2(key, timeout=0.1):
    """
    点击2次，隔一段时间，再松开
    """
    click(key, 0.1)
    time.sleep(0.1)
    click(key, timeout)


def code_list(player, target, speed: GameSpeed | int) -> list:
    """
    根据主角坐标和目标坐标，返回点击命令列表
    :param player 角色坐标
    :param target 目标坐标
    :param speed 角色移动速度
    """
    # zz_game.click(Key.right, 2.3) # 460
    # zz_game.click2(Key.right, 1.1)  # 970

    s = speed
    if isinstance(speed, GameSpeed):
        s = speed.value

    player_x, player_y = player
    target_x, target_y = target

    player_y = player_y

    span_x = abs(player_x - target_x)
    span_y = abs(player_y - target_y)
    arr = []

    x_key = Key.right
    if player_x > target_x:
        x_key = Key.left
    arr.append({
        "key": x_key,
        "timeout": zz_code.num1(span_x / s, 2),
    })

    # 上下移动无法跑
    y_key = Key.down
    if player_y > target_y:
        y_key = Key.up
    arr.append({
        "key": y_key,
        "timeout": zz_code.num1(span_y / GameSpeed.go.value, 2),
    })
    return arr


def get_pc_temp_file():
    """
    获取截屏文件
    """
    return zz_code.env("PC_TEMP_FILE")


class Game:
    def __init__(self, window: auto.PaneControl):
        self.window = window  #
        self.w = 1067
        self.h = 600
        self.play_hot = None
        self.play_hot_exists = False  # 特殊关卡已出现过
        self.player_xy = None  # 角色位置
        self.pic_main = None  # 截图数据 灰度
        self.pic_main_o = None  # 截图数据 原图
        self.mini_map_init_location = None  # 小地图初始坐标
        self.mini_map_data = [{
            "key": Key.right  # 第1张图传送口位置
        }]  # 小地图数据
        self.player_index = 0  # 第几个玩家
        self.player_blue_old_xy = None  # 玩家小蓝标xy
        self.play_index = 1  # 第几关
        self.player_data = None  # 玩家特殊数据

    def set_player_data(self, player_data):
        self.player_data = player_data  # 玩家特殊数据

    def player_data_curr(self) -> zz_player_data.PlayerData:
        if self.player_data is None or len(self.player_data) < self.player_index + 1:
            return zz_player_data.PlayerData()
        return self.player_data[self.player_index]

    def set_player_index(self, player_index):
        self.player_index = player_index

    def play1(self):
        """
        单个图处理
        """
        pass

    def play_ack_key(self):
        self.click_key('x')
        self.click_key('x')

    def set_play_index(self, play_index):
        self.play_index = play_index

    def get_name(self):
        return ""

    def handle(self):
        return self.handle_main()

    def handle_main(self):
        return False

    def get_pic_main(self, get_o=False):
        temp_file = get_pc_temp_file()
        if get_o:
            if self.pic_main_o is not None:
                return self.pic_main_o
        else:
            if self.pic_main is not None:
                return self.pic_main

        self.window.CaptureToImage(temp_file)
        if get_o:
            self.pic_main_o = zz_img_cv.load_img(temp_file)
            pic = self.pic_main_o
        else:
            self.pic_main = zz_img_cv.load_img(temp_file, cv2.IMREAD_GRAYSCALE)
            pic = self.pic_main
        return pic

    def img_find(self, img_target, threshold=0.8) -> zz_return.Return:
        # img_path = get_pc_temp_file()
        # self.window.CaptureToImage(img_path)
        img = self.get_pic_main()
        img_src = zz_img_cv.load_img(img, cv2.IMREAD_GRAYSCALE)
        r = zz_img_cv.find_img(img_src, img_target, threshold)
        return r

    def img_click_if_exists(self, msg, click_path, existe_path):
        """
        点击后，判断结果是否正确，否则重新点击
        :param msg:
        :param click_path: 点击图片
        :param existe_path: 点击后，期待出现的图片
        :return:
        """
        self.log_msg(msg)
        self.img_click(click_path)
        while not self.img_exit(existe_path):
            self.log_msg(f"{msg}-失败，再尝试")
            self.img_click(click_path)

    def img_click(self, img_target, threshold=0.8, index=0) -> bool:
        """
        点击图片，返回成功失败
        :param img_target:
        :param threshold:
        :param index: 点击找到目标的第index个
        """
        r = self.img_find(img_target, threshold)
        if r.err():
            self.log_msg(f"{img_target.split('/')[-1:][0]}-{r.get_errmsg()}")
            return False
        list = r.get_data("center_list")
        if len(list) < index:
            self.log_msg(f"图片标记异常{index}")
            return False
        x, y = list[index]
        self.window.Click(x, y)
        time.sleep(2)
        return True

    def img_exit(self, target_path, timeout=1.0, threshold=0.8) -> bool:
        """
        图片是否存在
        :param target_path:
        :param timeout: 等待时间（秒）
        :param threshold: 误差，1=100%
        """
        deadline = time.time() + timeout
        while True:
            r = self.img_find(target_path, threshold)
            if r.ok():
                return True

            if time.time() > deadline:
                break
            self.clear_tmp_data()
            time.sleep(0.5)
        return False

    def player_h(self):
        """
        角色身高
        """
        return self.player_data_curr().height

    def player_img(self):
        """
        角色图片路径
        """
        return self.player_data_curr().img

    def player_location(self) -> tuple:
        """
        角色坐标
        """
        if self.player_xy is not None:
            return self.player_xy

        keys = [Key.up, Key.down, Key.left]
        while True:
            r = self.img_find(self.player_img())
            if r.ok():
                x, y = r.get_data("first")
                y = y + self.player_h()  # 加角色身高
                self.log_msg(f"角色坐标[{x},{y}], 身高[{self.player_h()}], 速度[{self.player_speed_go()}]")
                self.player_xy = (x, y)
                return self.player_xy

            key = keys[random.randint(0, len(keys) - 1)]
            self.log_msg(f"获取角色坐标失败，移动再重新获取[{key}]")
            self.click_key(key, 0.1)

    def clear_tmp_data(self):
        """
        清理临时数据
        """
        self.pic_main = None
        self.pic_main_o = None
        self.player_xy = None

    def click_if_exist(self, msg, key, existe_path, click_time=0.1, count=1):
        """
        点击后判断是否存在某张图片
        """
        self.log_msg(msg)
        self.click_key(key, click_time)
        while not self.img_exit(existe_path):
            self.log_msg(f"{msg}-失败，再尝试")
            for i in range(count):
                self.click_key(key, click_time)
                time.sleep(0.3)
            time.sleep(2)

    def click_key(self, key, click_time=0.1, show_log=True):
        """
        移动
        """
        if show_log:
            self.log_msg(f"按：{key}--{click_time}ms")
        click(key, click_time)
        self.clear_tmp_data()

    def click_2key(self, key, clikc_time=0.1):
        """
        移动
        """
        click2(key, clikc_time)
        self.clear_tmp_data()

    def color_match(self, xy_top, xy_bottom, color) -> zz_return.Return:
        """
        颜色匹配
        """
        pic_main = self.get_pic_main(True)
        return zz_img_cv.color_match(pic_main, xy_top, xy_bottom, color)

    def player_speed_go(self):
        """
        走的速度
        """
        return self.player_data_curr().go

    def player_speed_run(self):
        """
        跑的速度
        """
        return self.player_speed_go() * 2.25

    def move(self, target_location, speed=GameSpeed.go):
        """
        控制角色移动到目标位置
        :param target_location: 目标坐标(120,455)
        :param speed: 角色移动速度，默认：走
        """
        # 速度重写
        if speed == GameSpeed.go:
            speed_x = self.player_speed_go()
        else:
            speed_x = self.player_speed_run()

        player = self.player_location()
        codes = code_list(player, target_location, speed_x)
        for code in codes:
            key = code['key']
            timeout = code['timeout']
            # log.info(f"{key}--{timeout}ms")
            if speed == GameSpeed.go:
                self.click_key(key, timeout)
            else:
                self.click_2key(key, timeout)

        return True

    def get_player_config(self, key=None) -> dict | None:
        """
        小地图参数
        """
        data = config_get(f"player_{self.player_index}")
        if data is None:
            data = {}

        if key is not None:
            if zz_code.dict_exists_key(data, key):
                return data[key]
            return None

        return data

    def set_player_config(self, k, v, exist_not_set=False):
        """
        :param exist_not_set: [true]值已存在不再设置新值
        """
        data = self.get_player_config()
        if exist_not_set and zz_code.dict_exists_key(data, k):
            return
        data[k] = v
        config_set(f"player_{self.player_index}", data)

    def exists_mini_map_data(self, k) -> bool:
        """
        key是否存在
        :param k:
        """
        mini_map_data = self.get_mini_map_data()
        return zz_code.dict_exists_key(mini_map_data, k)

    def get_mini_map_data_step(self) -> dict:
        mini_map_data = self.get_mini_map_data()
        try:
            step = mini_map_data['step']
        except Exception as ex:
            step = []
        return step

    def get_mini_map_data(self) -> dict:
        """
        小地图参数
        """
        mini_map_data = config_get("mini_map")
        if mini_map_data is None:
            return {}
        return mini_map_data

    def set_mini_map_data(self, k, v):
        mini_map_data = self.get_mini_map_data()
        mini_map_data[k] = v
        config_set("mini_map", mini_map_data)

    def clear_min_map_data(self):
        config_set("mini_map", None)

    def mini_map_find_blue(self) -> list:
        """
        获取小地图，蓝图标位置
        """
        # 滤过黑屏时间
        self.img_exit("./game/img/mini_map_end.png", 5)

        res = [-1, -1]
        try_count = 0
        while True:
            pic_main_o = self.get_pic_main()
            r = zz_img_cv.find_img(pic_main_o, "./game/img/play_location.png")
            if r.ok():
                res = r.get_data("first")
                break
            if self.play_index == 5:
                # boss图
                res = [-2, -2]
                break

            if not self.is_play_hot() and try_count < 2:
                self.log_msg('非特殊关卡，[-1,-1]定位失败，重新获取')
                self.clear_tmp_data()
                try_count += 1
                continue
            res = [-1, -1]
            break
        return res

    def mini_map(self, o=True):
        """
        获取最新小地图
        """
        if not self.exists_mini_map_data('first') or not self.exists_mini_map_data("end"):
            pic_main = self.get_pic_main()
            r = zz_img_cv.find_img(pic_main, "./game/img/mini_map_begin.png")
            begin_x, begin_y = r.get_data("first")
            r = zz_img_cv.find_img(pic_main, "./game/img/mini_map_end.png")
            end_x, end_y = r.get_data("first")
            x, y = min(end_x, begin_x), min(end_y, begin_y)
            x_max, y_max = max(end_x, begin_x), max(end_y, begin_y)
            # 小地图坐标
            self.set_mini_map_data('first', (x, y))
            self.set_mini_map_data('end', (x_max, y_max))
            # 记录起始坐标
            self.set_mini_map_data('init', (abs(begin_x - x), abs(begin_y - y)))
            self.set_mini_map_data('step', [])
            self.set_mini_map_data('step_old', [])

        mini_map_data = self.get_mini_map_data()
        x, y = mini_map_data['first']
        w, h = (107, 36)

        pic_main_0 = self.get_pic_main(o)
        return pic_main_0[y:y + h, x:x + w]

    def mini_map_from_next(self, init_xy=None, mini_map=None, step=None):
        """
        根据小地图获取方向
        :param mini_map: 小地图
        :param step: 小地图传送口数据
        """
        self.log_msg("开始分析小地图，获取传送口方向")
        if mini_map is None:
            mini_map = self.mini_map()
        mini_map_data = self.get_mini_map_data()
        if init_xy is None:
            init_xy = mini_map_data['init']
        if step is None:
            step = mini_map_data['step']

        mini_w = 17  # 小地图每小块长高都是17
        # next_color = [(181, 159, 150), (179, 158, 149), (195, 175, 168), (188, 168, 160)]
        next_color = [(181, 159, 150)]
        x, y = init_xy
        # print(x, y)
        last_key = Key.right
        for item in step:
            if item['key'] == 'right':
                x += mini_w + 1
            elif item['key'] == 'up':
                y -= mini_w + 1
            elif item['key'] == 'down':
                y += mini_w + 1
            last_key = item['key']
        # print(x, y)
        # 判断上下右的像素
        # 右
        img_top_right = (x + mini_w, y)
        img_bottom_right = (x + mini_w, y + mini_w)
        self.log_msg(f"判断右：{img_top_right}--{img_bottom_right}")
        r = zz_img_cv.color_match(mini_map, img_top_right, img_bottom_right, next_color)
        if r.ok():
            r.set_errmsg("传送口在右边")
            r.set_data("key", "right")
            return r
        # 下
        img_top_down = (x, y + mini_w)
        img_bottom_down = (x + mini_w, y + mini_w)
        self.log_msg(f"判断下：{img_top_down}--{img_bottom_down}")
        r = zz_img_cv.color_match(mini_map, img_top_down, img_bottom_down, next_color)
        if r.ok():
            r.set_errmsg("传送口在下边")
            r.set_data("key", "down")
            return r
        # 上
        img_top_up = (x, y)
        img_bottom_up = (x + mini_w, y)
        self.log_msg(f"判断上：{img_top_up}--{img_bottom_up}")
        r = zz_img_cv.color_match(mini_map, img_top_up, img_bottom_up, next_color)
        if r.ok():
            r.set_errmsg("传送口在上边")
            r.set_data("key", "up")
            return r

        self.log_msg(f"获取传送口位置失败，可能存在水晶，进行问号判断")
        r = zz_img_cv.find_img(self.mini_map(False), './game/img/play_done.png')
        if r.ok():
            done_x, done_y = r.get_data("first")
            r = zz_return.of(0)
            r.set_data("x", (x, y))
            r.set_data("done", (done_x, done_y))
            self.log_msg(f"小地图坐标{r.get_data('x')}，问号坐标{r.get_data('done')}")
            if y == done_y or y == done_y - 1 or y == done_y + 1:
                r.set_errmsg("传送口在右边")
                r.set_data("key", "right")
            elif y < done_y:
                r.set_errmsg("传送口在下边")
                r.set_data("key", "down")
            else:
                r.set_errmsg("传送口在上边")
                r.set_data("key", "up")
            return r

        if self.play_index == 1:
            self.log_msg(f"图1，直接返回右")
            r = zz_return.of(0)
            r.set_data("key", "right")
            return r

        if len(step) >= 4:
            self.log_msg(f"boss图，直接返回右")
            r = zz_return.of(0)
            r.set_data("key", "right")
            return r

        self.log_msg(f"获取传送口位置失败，盲猜右边")
        # if self.is_play_hot():
        #     r = zz_return.of(0)
        #     r.set_data("key", "right")
        #     self.mini_map_save(mini_map)
        # else:
        #     r = zz_return.of(20525, "获取传送口位置失败，盲猜右边")
        r = zz_return.of(20525, "获取传送口位置失败，盲猜右边")
        self.mini_map_save(mini_map)

        return r

    def mini_map_save(self, mini_map=None):
        if mini_map is None:
            mini_map = self.mini_map()
        cv2.imwrite(f'./../_tmp/game_next_{zz_code.date_tostring(None, "%Y%m%d_%H%M%S")}.png', mini_map)

    def mini_map_from_next2(self, start_xy: tuple):
        mini_w = 17
        self.log_msg(f"右边：{start_xy}")
        mini_map_o = self.mini_map(False)
        wen = mini_map_o[start_xy[1]: start_xy[1] + mini_w, start_xy[0]:start_xy[0] + mini_w + 1]
        cv2.imwrite(f'./../_tmp/wen.png', wen)
        return zz_img_cv.find_img(wen, './game/img/play_done.png')

    def reset_play_hot(self):
        """
        重置特殊关卡状态
        """
        if self.play_hot_exists:
            # 已出现过，不重置
            pass
        else:
            self.play_hot = None

    def is_play_hot(self):
        if self.play_hot is None:
            self.play_hot = self.img_exit("./game/img/play_hot.png", 0.5)
        self.log_msg(f"存在特殊关卡: {self.play_hot}")
        return self.play_hot

    def play_done(self):
        done = self.img_exit("./game/img/play_done.png")
        self.log_msg(f"战斗状态: {done}")
        return done

    def move_next_done(self):
        """
        判断小地图玩家小图标移动，视为已过图
        """
        player_blue_new = self.mini_map_find_blue()
        self.player_blue_old_xy = self.get_mini_map_data()["player"]
        ok = False
        if player_blue_new != self.player_blue_old_xy:
            self.set_mini_map_data("player", player_blue_new)
            ok = True
        self.log_msg(f"过图状态：{ok} -- {self.player_blue_old_xy}-{player_blue_new}")
        return ok

    def move_center_left(self):
        """
        移动到左边中间
        """
        y = 460
        if self.is_play_hot():
            y = 600  # 特殊关卡，往下走
        self.move((350, y), GameSpeed.run)
        self.click_key(Key.right)

    def move_center_rigth(self):
        y = 460
        self.move((self.w - 300, y), GameSpeed.run)
        self.click_key(Key.left)

    def move_next_check(self):
        """
        判断是否跑错图
        """
        if self.play_index == 1:
            # 图1不检查
            return True
        mini_map_step = self.get_mini_map_data()['step']  # 当前玩家坐标
        mini_map_step_old = self.get_mini_map_data()['step_old']  # 历史玩家坐标
        next_ok = True
        next_err_index = 0
        player_blue_new_xy = self.get_mini_map_data()["player"]
        mini_map_step_new = []
        for i in range(len(mini_map_step_old)):
            item = mini_map_step_old[i]
            next_err_index = i + 1
            if player_blue_new_xy == item['location']:
                next_ok = False
                break
            mini_map_step_new.append(item)
        if not next_ok:
            self.set_mini_map_data('step', mini_map_step)
            self.set_play_index(next_err_index)
            self.log_msg(f"角色跑错了，进入{next_err_index}图")
            self.set_mini_map_data('step', mini_map_step_new)
        return next_ok

    def move_next(self) -> int:
        """
        【1】成功；【0】失败；【2】再运行1次；
        """
        self.log_msg("获取传送口位置")
        r = self.mini_map_from_next()
        if r.err():
            raise ValueError("获取传送口位置失败")

        self.log_msg(f"传送口方向: {r.get_data('key')}")
        if not self.exists_mini_map_data('player'):
            self.set_mini_map_data('player', self.mini_map_find_blue())

        key = r.get_data("key")
        run_all = 0
        run = 0
        while True:
            if run_all > 2:
                self.log_msg(f"一直无法进入下一个图，回到中心位置")
                self.move_center_rigth()
                self.play_ack_key()
                self.get_prize()

                next_ok = self.move_next_check()
                if not next_ok:
                    return 0

                return 2

            if key == "right":
                target = (self.w - 20, 450)  # 地图高度中心
                if run > 1:
                    run = 0
                    # 往下走
                    target = (self.w - 20, self.h)
                self.log_msg(f"向右走{target}")
            elif key == "up":
                target = (self.w / 2, 300)
                self.log_msg(f"向上走{target}")
            elif key == "down":
                target = (self.w / 2 + 100, self.h)
                if run > 1:
                    run = 0
                    target = (self.w / 2 + 500, self.h)
                self.log_msg(f"向下走-{target}")
            else:
                self.log_msg("获取传送口位置失败")
                break
            self.log_msg(f"传送口坐标: {target}")
            self.move(target, GameSpeed.run)
            time.sleep(0.2)
            # self.click_key('x')
            run += 1
            run_all += 1

            if self.move_next_done():
                break
            if not self.is_play_hot():
                time.sleep(2)
            else:
                time.sleep(0.5)

        mini_map_step = self.get_mini_map_data()['step']  # 当前玩家坐标
        mini_map_step_old = self.get_mini_map_data()['step_old']  # 历史玩家坐标

        # 判断是否真的进入下一个图
        next_ok = self.move_next_check()
        if not next_ok:
            return 0

        # 保存step
        step_item = {
            'key': key,
            'location': self.player_blue_old_xy
        }
        mini_map_step.append(step_item)
        self.set_mini_map_data('step', mini_map_step)
        if len(mini_map_step_old) < self.play_index:
            mini_map_step_old.append(step_item)
            self.set_mini_map_data('step_old', mini_map_step_old)
        # 更新玩家图标位置
        blue = self.mini_map_find_blue()
        self.set_mini_map_data('player', blue)
        self.log_msg(f"已进入下一个图{blue}")
        return 1

    def get_prize(self, auto=False):
        """
        获取图中所有物品
        :param auto true 捡图中所有物品;
        """
        prize_name = '物品'

        all = 0
        get1_count = 0  # 捡同一个物品次数
        get1_x = 0
        prize_xy_old = None
        self.log_msg(f"检查掉落{prize_name}")
        if self.is_play_hot():
            self.log_msg(f"特殊关卡，不捡物品")
            return

        do_auto = auto
        while True:
            r = self.img_find("./game/img/prize_01.png", 0.9)
            if r.err():
                self.log_msg(f"图中无掉落{prize_name}")
                break

            if all > 20:
                self.log_msg(f"捡物品超20次，直接跳出，防卡死")
                break
            if do_auto:
                self.click_key("4")
                time.sleep(2)
                do_auto = False  # 只做1次
                self.click_key(Key.up, 0.2)
            else:
                prize_x, prize_y = r.get_data("first")
                if prize_xy_old == [prize_x, prize_y]:
                    self.log_msg('同一个物品多次捡不到，物品名字太长，加x')
                    get1_count += 1
                    get1_x += 10
                else:
                    get1_count = 0
                    get1_x = 0
                    prize_xy_old = [prize_x, prize_y]

                prize_y += 50  # 物品高度
                self.log_msg(f"物品坐标[{prize_x + get1_x},{prize_y}]")
                self.move((prize_x + get1_x, prize_y))
                self.click_key("x")
            all += 1
            time.sleep(0.3)
        self.log_msg(f"检查掉落{prize_name}--完成")

    def game_end(self, pic_main=None):
        """
        判断是否还能再战
        """
        if pic_main is None:
            pic_main = self.get_pic_main(True)
        xy = (903, 84)
        color = [[108, 110, 108]]
        r = zz_img_cv.color_match(pic_main, xy, xy, color)
        return r.ok()

    def game_f10(self):
        """
        再次挑战
        """
        while True:
            self.click_key(Key.f10)
            time.sleep(1)
            #
            self.clear_tmp_data()
            # xy = (902, 84)
            # color = [[0, 2, 0]]
            xy = (976, 85)
            color = [[254, 248, 156]]
            r = self.color_match(xy, xy, color)
            if r.ok() or not self.img_exit('./game/img/f10_alert.png', 2):
                self.log_msg("再次挑战成功")
                break
            else:
                self.log_msg("再次挑战失败，再按f10")
            time.sleep(1)

    def upkeep(self):
        """
        装备维修
        """
        v = self.get_player_config("upkeep")
        if v is not None and v == 1:
            # 已维修过
            return
        self.log_msg("装备维修")
        self.click_key("s")
        time.sleep(1)
        self.click_key(Key.space)
        time.sleep(1)
        self.set_player_config("upkeep", 1)

    def prize_buy(self, buy=False):
        """
        取消商店弹窗,并卖装备
        """
        if self.img_exit("./game/img/play_done_store.png", 2):
            self.log_msg("存在商店点击")
            if self.game_end():
                self.log_msg("已完成战斗，再卖1次装备")
                buy = True

            self.upkeep()

            if buy:
                self.log_msg('需要卖装备,全选装备')
                self.click_key("a")
                time.sleep(1)
                self.log_msg('空格确定')
                self.click_key(Key.space)
                time.sleep(1)
                self.log_msg('空格再次确定')
                self.click_key(Key.space)
                time.sleep(0.3)
                self.click_key(Key.esc)
            while self.img_exit("./game/img/play_done_store.png", 1):
                self.log_msg('取消商店弹窗')
                self.click_key(Key.esc)
                time.sleep(0.3)

    def player_select(self, index):
        """
        人物选择
        :param index: 选择第几个角色
        """
        self.click_if_exist("打开菜单", Key.esc, "./game/img/menu_next.png")
        self.img_click_if_exists("点击选择角色", "./game/img/menu_player.png", "./game/img/home_main.png")
        time.sleep(0.5)
        self.click_key(Key.down)
        time.sleep(0.5)
        w = 125
        h = 207
        init_x = 42 + index * 142  # w+17
        init_y = 127 + int(index / 7) * 217  # h+17
        center_x = int(init_x + w / 2)
        center_y = int(init_y + h / 2)
        # 判断是否已经可选的角色
        color = [[7, 8, 10]]
        r = self.color_match((center_x, center_y), (center_x, center_y), color)
        if r.ok():
            self.log_msg(f"第{index}角色，不存在，返回")
            self.click_key(Key.space)
            return False

        # color = [[7, 8, 10]]
        # r = zz_img_cv.color_match(pic_main, xy, xy, color)
        self.log_msg(f"点击选择第{index}角色{(init_x, init_y)}")
        self.window.Click(center_x, center_y)
        time.sleep(2)
        self.click_if_exist("开始游戏", Key.space, "./game/img/home_main_01.png")
        self.log_msg("选择角色完成")
        return True

    def log_msg(self, msg):
        """
        输出日志，统一格式
        :param msg:
        """
        log.info(f"{self.get_name()}[{self.play_index}]---{msg}")


config = None
config_path = zz_code.env("CONFIG_PATH")


def config_path_set(path):
    """
    设置配置路径
    """
    global config_path
    config_path = path
    config_to_return(True)


def config_to_return(get_file=False) -> zz_return.Return:
    """
    配置 转 r
    :return:
    """
    global config
    config_file_path = config_path
    config_delete()

    if config is None or get_file:
        config = ""
        try:
            with open(config_file_path, 'r', encoding='utf-8') as file:
                lines = file.readlines()
                for line in lines:
                    config += line
        except Exception as ex:
            traceback.print_exc()
    return zz_return.parse(config)


def config_get(k):
    """
    获取配置
    :param k:
    """
    r = config_to_return()
    val = r.get_data(k)
    if isinstance(val, str):
        val = val.strip()

    return val


def config_clear():
    global config
    config = None


def config_set(k, v):
    """
    保存配置
    :param k:
    :param v:
    """
    global config

    r = config_to_return()
    r.set_data(k, v)
    r.data.pop("errcode")
    r.data.pop("errmsg")
    #
    config = r.to_json()
    file = open(config_path, "w", encoding="utf-8")
    # 写入数据
    file.write(config)
    # 关闭文件
    file.close()


def config_delete():
    """
    删除旧日志
    :param threshold_days: 删除n天前文件（修改时间）
    """
    delete_date = zz_code.date_sub_day(zz_code.date_today(), 0)
    files = glob.glob("./game_*.json")
    for file in files:
        if os.path.isfile(file):
            file_create_date = zz_code.date_from_timestamp(os.path.getmtime(file))
            if file_create_date < delete_date:
                os.remove(file)
